package com.kdyzm.code.backup.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.kdyzm.http.HttpRequest;
import cn.kdyzm.http.LogLevel;
import com.fasterxml.jackson.core.type.TypeReference;
import com.kdyzm.code.backup.model.ProjectItem;
import com.kdyzm.code.backup.model.SubGroup;
import com.kdyzm.code.backup.properties.GitlabProperties;
import com.kdyzm.code.backup.service.GitlabService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.print.attribute.standard.PagesPerMinute;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author kdyzm
 * @date 2023/9/20
 */
@Service
@Slf4j
@AllArgsConstructor
public class GitlabServiceImpl implements GitlabService {

    private final GitlabProperties gitlabProperties;

    private static final int pageSize = 20;

    @Override
    public void startClone() {

        String groups = gitlabProperties.getGroups();
        if (StrUtil.isBlank(groups)) {
            log.error("config group is not allowed empty");
            return;
        }
        for (String groupName : groups.split(",")) {
            groupName = groupName.trim();
            String topGroup = groupName.split("/")[0];
            SubGroup groupDeatil = getGroupDeatil(topGroup);
            String groupId = getGroupId(topGroup, groupDeatil.getId(), groupName);
            clone(groupName, groupId);
        }
    }

    private void clone(String parentDir, String groupId) {
        List<ProjectItem> projects = getProjects(groupId);
//        log.info("获取到项目数：{}", projects.size());
        doClone(parentDir, projects);
        List<SubGroup> subGroups = getSubGroups(groupId);
        if (CollUtil.isNotEmpty(subGroups)) {
            for (SubGroup subGroup : subGroups) {
                clone(subGroup.getFullPath(), subGroup.getId());
            }
        }
    }

    private void doClone(String parentDirName, List<ProjectItem> projects) {
        //如果配置了路径，使用路径配置
        if (StrUtil.isNotBlank(gitlabProperties.getTargetDir())) {
            parentDirName = gitlabProperties.getTargetDir() + "\\" + parentDirName;
        }
        File parentDir = new File(parentDirName);
        if (!parentDir.exists()) {
            parentDir.mkdirs();
        }
        for (ProjectItem project : projects) {
            String name = project.getName();
            File repositoryDir = new File(parentDir, name);
            if (repositoryDir.exists()) {
                updateRepository(repositoryDir);
            } else {
                cloneRepository(project.getHttpUrlToRepo(), parentDirName);
            }
        }

    }

    private void updateRepository(File repositoryDir) {
        try {
            log.info("开始更新代码仓库：{}", repositoryDir.getAbsolutePath());
            ProcessBuilder processBuilder = new ProcessBuilder();
            processBuilder.command("git", "fetch");
            processBuilder.directory(repositoryDir);
            Process process = processBuilder.start();
            int exitCode = process.waitFor();
            if (exitCode == 0) {
                log.info("代码仓库:{} 更新成功", repositoryDir.getAbsolutePath());
            } else {
                log.info("代码仓库:{} 更新失败", repositoryDir.getAbsolutePath());
            }
        } catch (IOException | InterruptedException e) {
            log.error("", e);
        }
    }

    public void cloneRepository(String repositoryUrl, String targetDirectory) {
        try {
            ProcessBuilder processBuilder = new ProcessBuilder();
            processBuilder.command("git", "clone", repositoryUrl);
            log.info("开始克隆项目{} 到文件夹 {}", repositoryUrl, targetDirectory);
            processBuilder.directory(new File(targetDirectory));

            Process process = processBuilder.start();

            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                log.info(line);
            }

            int exitCode = process.waitFor();
            if (exitCode == 0) {
                log.info("代码仓库:{} 克隆成功", repositoryUrl);
            } else {
                log.info("代码仓库:{} 克隆失败", repositoryUrl);
            }
        } catch (IOException | InterruptedException e) {
            log.error("", e);
        }
    }


    @Override
    public String getGroupId(String fullPath, String groupId, String aimFullPath) {
        List<SubGroup> subGroups = getSubGroups(groupId);
        if (fullPath.equals(aimFullPath)) {
            return groupId;
        }
        for (SubGroup subGroup : subGroups) {
            String groupId1 = getGroupId(subGroup.getFullPath(), subGroup.getId(), aimFullPath);
            if (StrUtil.isNotEmpty(groupId1)) {
                return groupId1;
            }
        }
        return null;
    }


    @Override
    public List<SubGroup> getSubGroups(String groupName) {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        int page = 1;

        String url = gitlabProperties.getBaseUrl() + "/api/v4/groups/" + groupName + "/subgroups";
        Map<String, Object> params = new HashMap<>(2);

        params.put("page", page);
        params.put("per_page", pageSize);

        List<SubGroup> subGroups;
        List<SubGroup> data = new ArrayList<>();
        do {
//            log.info("查询第【{}】页 subgroups", page);
            subGroups = HttpRequest.get(url)
                    .addHeader("Private-Token", gitlabProperties.getToken())
                    .queryMap(params)
                    .log(LogLevel.BASIC)
                    .execute()
                    .asValue(
                            new TypeReference<List<SubGroup>>() {
                            }
                    );
            data.addAll(subGroups);
            page++;
            params.put("page", page);
        } while (CollUtil.isNotEmpty(subGroups));
        return data;
    }


    @Override
    public List<ProjectItem> getProjects(String groupId) {
        String url = gitlabProperties.getBaseUrl() + "/api/v4/groups/" + groupId + "/projects";

        Map<String, Object> params = new HashMap<>(2);

        int page = 1;
        params.put("page", page);
        params.put("per_page", pageSize);

        List<ProjectItem> items;
        List<ProjectItem> data = new ArrayList<>();
        do {
//            log.info("开始查询第【{}】页项目列表", page);
            items = HttpRequest.get(url)
                    .addHeader("Private-Token", gitlabProperties.getToken())
                    .queryMap(params)
                    .log(LogLevel.BASIC)
                    .execute()
                    .asValue(
                            new TypeReference<List<ProjectItem>>() {
                            }
                    );
            data.addAll(items);
            page++;
            params.put("page", page);
        } while (CollUtil.isNotEmpty(items));
        return data;
    }

    public SubGroup getGroupDeatil(String id) {
        String url = gitlabProperties.getBaseUrl() + "/api/v4/groups/" + id;
        return HttpRequest.get(url)
                .addHeader("Private-Token", gitlabProperties.getToken())
                .log(LogLevel.BASIC)
                .execute()
                .asValue(
                        new TypeReference<SubGroup>() {
                        }
                );
    }
}
